﻿using DG.Tweening;
using FixMath.NET;
using GameLogic.Localization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using TEngine;
using UnityEngine;

namespace GameLogic
{
    public class GlobalFunction
    {
        
        public enum ClientType
        {
            Client,
            Server,
        }

        public static GameObject PlayEffect(string path, bool autoDestory = true)
        {
            var m_CurObj = PoolManager.Instance.GetGameObject(path);
            if (!m_CurObj)
                return null;
            var duration = GetEffectsDuration(m_CurObj, 0);

            if(autoDestory)
            {
                DOVirtual.DelayedCall(duration, () => {
                    PoolManager.Instance.PushGameObject(m_CurObj);
                });
            }
            return m_CurObj;
        }

        static float GetEffectsDuration(GameObject obj, float duration)
        {
            for (int i = 0; i < obj.transform.childCount; i++)
            {
                var childTr = obj.transform.GetChild(i);
                duration = GetEffectsDuration(childTr.gameObject, duration);
            }
            var particleSystem = obj.GetComponent<ParticleSystem>();
            if (!particleSystem)
                return duration;
            ParticleSystemRenderer renderer = particleSystem.GetComponent<ParticleSystemRenderer>();
            if (duration < particleSystem.main.duration)
                duration = particleSystem.main.duration;
            if (duration < particleSystem.main.startLifetime.constantMax)
                duration = particleSystem.main.startLifetime.constantMax;

            return duration;
        }
        public static int PlusLengthHeadToByteArray(byte[] array, byte[] data)
        {
            UInt16 dataLength = (UInt16)data.Length;
            Array.Copy(BitConverter.GetBytes(dataLength), array, 2);
            Array.Copy(data, 0, array, 2, dataLength);
            return dataLength + 2;
        }
        public static string GetLanguage(string key)
        {
            return LLocalizationManager.Instance.GetString(key);
        }
        /// <summary>
        /// 数字换算
        /// </summary>
        /// <param name="num"></param>
        /// <returns></returns>
        public static string Numdispose(string num)
        {
            bool isMinus = num[0] == '-';
            num = isMinus ? num.Substring(1) : num;
            string[] symbol = new string[num.Length * 3];
            string n1 = "a";
            string n2 = "a";
            string n3 = "a";
            for (int i = 0; i < symbol.Length; ++i)
            {
                symbol[i] = LLocalizationManager.Instance.GetString("money_unit_" + n1 + n2 + n3);
                n3 = ((Char)(n3[0] + 1)).ToString();
                if (n3[0] > 'z')
                {
                    n3 = "a";
                    n2 = ((Char)(n2[0] + 1)).ToString();
                }
                if (n2[0] > 'z')
                {
                    n2 = "a";
                    n1 = ((Char)(n1[0] + 1)).ToString();
                }
            }
            string str1 = string.Empty;

            string str2 = string.Empty;

            int unitCount = 3;
            string localizationUnitCount = LLocalizationManager.Instance.GetString("money_unit_change");
            if (int.TryParse(localizationUnitCount, out int parseCount))
                unitCount = parseCount;
            int reservedBit = 4;
            if (num.Length > reservedBit && num.Length > unitCount)
            {
                reservedBit = (num.Length % reservedBit == 0) ? reservedBit : num.Length % reservedBit;
                int unitIdx = (num.Length - reservedBit) / unitCount - 1;

                str1 = num.Substring(0, reservedBit);

                int behindDotIdx = reservedBit;
                if (behindDotIdx < num.Length)
                    str1 += "." + num[behindDotIdx];

                return (isMinus ? "-" : "") + str1 + symbol[unitIdx];
            }
            return (isMinus ? "-" : "") + num;
        }

        //public static string ToTimeThreeFormat(long timer)
        //{
        //    long s = timer;
        //    long hour = s / 3600;
        //    long minute = s % 3600 / 60;
        //    long second = s % 3600 % 60;
        //    return StringHelper.Format("{0:D2}:{1:D2}:{2:D2}", hour, minute, second);
        //}

    static public string GetMACAddress()
    {
        string macAddress = "";
        foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
        {
            if (nic.OperationalStatus == OperationalStatus.Up)
            {
                macAddress = nic.GetPhysicalAddress().ToString();
                break;
            }
        }
        return macAddress;
    }


    //获取本机的ip地址
    public static string GetLocalIP()
        {

            IPAddress[] ips = Dns.GetHostAddresses(Dns.GetHostName());
            for (int i = 0; i < ips.Length; i++)
            {
                IPAddress address = ips[i];
                if (address.AddressFamily == AddressFamily.InterNetwork)
                {
                    return address.ToString();//返回ipv4的地址的字符串
                }
            }
            //找不到就返回本地
            return "127.0.0.1";
        }
        public static Vector2Int ParseToVector2Int(string str)
        {
            var strs = str.Split(',');
            return new Vector2Int(int.Parse(strs[0]), int.Parse(strs[1]));
        }
        public static BEPUutilities.Vector2 ParseFixPos(string str)
        {
            var strs = str.Split(',');
            return new BEPUutilities.Vector2(Fix64.Parse(strs[0]), Fix64.Parse(strs[1]));
        }
        public static string Vector2IntToString(Vector2Int vec)
        {
            return vec.x + "," + vec.y;
        }
        public static List<Vector2> GetSpritePhysicsPathPoints(Sprite sprite)
        {
            if (sprite.GetPhysicsShapeCount() <= 0)
                return sprite.vertices.ToList();
            var shapePointCount = sprite.GetPhysicsShapePointCount(0);
            List<Vector2> vec = new List<Vector2>();
            sprite.GetPhysicsShape(0, vec);
            return vec;

        }

        static bool pointTriangleInside(Vector3 P, Vector3 A, Vector3 B, Vector3 C)
        {
            Vector3 v0 = C - A;
            Vector3 v1 = B - A;
            Vector3 v2 = P - A;

            float dot00 = Vector3.Dot(v0, v0);
            float dot01 = Vector3.Dot(v0, v1);
            float dot02 = Vector3.Dot(v0, v2);
            float dot11 = Vector3.Dot(v1, v1);
            float dot12 = Vector3.Dot(v1, v2);

            float inverDeno = 1 / (dot00 * dot11 - dot01 * dot01);

            float u = (dot11 * dot02 - dot01 * dot12) * inverDeno;
            if (u < 0 || u > 1) // if u out of range, return directly
            {
                return false;
            }

            float v = (dot00 * dot12 - dot01 * dot02) * inverDeno;
            if (v < 0 || v > 1) // if v out of range, return directly
            {
                return false;
            }

            return u + v <= 1;
        }

        public static uint GetRandomID()
        {
            Guid sessionID = Guid.NewGuid();
            //var sessionID = GetMACAddress();
            byte[] sessionIdBytes = Encoding.UTF8.GetBytes(sessionID.ToString());
            return BitConverter.ToUInt32(sessionIdBytes, 0);
        }

        //	\brief	将点进行顺时针排序
        static bool sortPoints(List<Vector3> points)
        {
            bool isSort = false;
            //顺时针排序(先找到一个凸点p，然后得到(p-1,p) , (p, p+1)两个向量进行叉乘得到多边形绕序)
            if (points.Count >= 3)
            {
                int p = 0;
                for (int i = 0; i < points.Count; ++i)
                {
                    Vector3 posMax = points[p];
                    Vector3 pos = points[i];
                    if (pos.x != 0 && pos.y != 0 && pos.x > posMax.x)
                    {
                        p = i;
                    }
                }

                int ps1 = p == 0 ? (points.Count - 1) : (p - 1);
                int pp1 = p == (points.Count - 1) ? 0 : (p + 1);

                Vector3 pPos = points[p];
                Vector3 ps1Pos = points[ps1];
                Vector3 pp1Pos = points[pp1];

                ps1Pos = ps1Pos - pPos;
                pp1Pos = pPos - pp1Pos;

                Vector3 crossResult = Vector3.Cross(ps1Pos, pp1Pos);
                if (crossResult.z > 0)
                {
                    List<Vector3> copy = points;
                    for (int i = 0; i < copy.Count; ++i)
                    {
                        points[i] = copy[copy.Count - i - 1];
                    }
                    isSort = true;
                }
            }
            return isSort;
        }
        static List<int> calcPolygon(List<Vector2> points)
        {
            List<Vector3> points3D = new List<Vector3>();
            foreach (var i in points)
            {
                points3D.Add(i);
            }
            return calcPolygon(points3D);
        }
        //	\brief	根据多边形顶点计算多边形三角面索引
        static List<int> calcPolygon(List<Vector3> points)
        {
            //顺时针排序(先找到一个凸点p，然后得到(p-1,p) , (p, p+1)两个向量进行叉乘得到多边形绕序)
            sortPoints(points);

            //	构建三角面
            List<int> indexes = new List<int>();
            List<KeyValuePair<int, Vector3>> vetricesMap = new List<KeyValuePair<int, Vector3>>();
            for (int i = 0; i < points.Count; ++i)
            {
                vetricesMap.Add(new KeyValuePair<int, Vector3>(i, points[i]));
            }
            bool isActivity = true;
            while (isActivity)
            {
                isActivity = false;
                for (int i = 0; i < (vetricesMap.Count - 2); ++i)
                {
                    Vector3 p0 = vetricesMap[i + 0].Value;
                    Vector3 p1 = vetricesMap[i + 1].Value;
                    Vector3 p2 = vetricesMap[i + 2].Value;

                    Vector3 A = p1 - p0;
                    Vector3 B = p2 - p1;
                    Vector3 result = Vector3.Cross(A, B);

                    //	如果三角面中有其他的点，则不处理
                    bool isHaveTriangular = false;
                    for (int j = 0; j < points.Count; ++j)
                    {
                        if (j == vetricesMap[i + 0].Key ||
                            j == vetricesMap[i + 1].Key ||
                            j == vetricesMap[i + 2].Key)
                        {
                            continue;
                        }
                        isHaveTriangular = pointTriangleInside(points[j], p0, p1, p2);
                        if (isHaveTriangular)
                        {
                            break;
                        }
                    }
                    if (result.z <= 0 && !isHaveTriangular)
                    {
                        indexes.Add(vetricesMap[i + 2].Key);
                        indexes.Add(vetricesMap[i + 1].Key);
                        indexes.Add(vetricesMap[i + 0].Key);
                        vetricesMap.Remove(vetricesMap[i + 1]);
                        isActivity = true;
                    }
                }
            }
            return indexes;
        }





        static bool IsPointInsideContour(Vector2 point, List<Vector2> contour)
        {
            int intersections = 0;
            int n = contour.Count;
            for (int i = 0, j = n - 1; i < n; j = i++)
            {
                if ((contour[i].y > point.y) != (contour[j].y > point.y) &&
                    point.x < (contour[j].x - contour[i].x) * (point.y - contour[i].y) / (contour[j].y - contour[i].y) + contour[i].x)
                {
                    intersections++;
                }
            }
            return intersections % 2 == 1;
        }

        public static Mesh GenerateMesh(List<Vector2> contourPoints)
        {
            Mesh mesh = new Mesh();
            List<Vector3> vertices = new List<Vector3>();
            List<int> triangles = new List<int>();
            List<Vector2> uvs = new List<Vector2>();
            var resolution = 100;
            float step = 1.0f / resolution;
            for (int y = 0; y <= resolution; y++)
            {
                for (int x = 0; x <= resolution; x++)
                {
                    float px = x * step;
                    float py = y * step;
                    Vector2 point = new Vector2(px, py);

                    // 检查点是否在轮廓内
                    if (IsPointInsideContour(point, contourPoints))
                    {
                        vertices.Add(new Vector3(px, py, 0));
                        uvs.Add(new Vector2(px, py));

                        // 添加三角形索引
                        if (x < resolution && y < resolution)
                        {
                            int index = vertices.Count - 1;
                            triangles.Add(index);
                            triangles.Add(index + resolution + 1);
                            triangles.Add(index + resolution);

                            triangles.Add(index);
                            triangles.Add(index + 1);
                            triangles.Add(index + resolution + 1);
                        }
                    }
                }
            }

            mesh.vertices = vertices.ToArray();
            mesh.triangles = triangles.ToArray();
            mesh.uv = uvs.ToArray();
            mesh.RecalculateNormals();
            mesh.RecalculateBounds();
            return mesh;
        }
        public static Mesh GeneratePhysicsMeshOfSprite(Sprite sprite)
        {
            var pathPoints = GlobalFunction.GetSpritePhysicsPathPoints(sprite);

            var pathPointsAll = new List<Vector3>();
            var pathPoints1 = new List<Vector3>();
            var pathPoints2 = new List<Vector3>();
            foreach(var i in pathPoints)
            {
                pathPoints1.Add(i);
                pathPoints2.Add(new Vector3(i.x, i.y, 1) );
            }

            var indxs = new List<int>();
            var indxs1 = calcPolygon(pathPoints);
            var indxs2 = new List<int>();
            var indexWall = new List<int>();
            for(var i= indxs1.Count-1; i>=0; --i)
            {
                indxs2.Add(indxs1[i] + pathPoints1.Count);
            }
            for (var i = 0; i < pathPoints1.Count; ++i)
            {
                int index = i;
                int nextIndex = i+1;
                if (nextIndex >= pathPoints1.Count)
                    nextIndex = 0;
                indexWall.Add(index);
                indexWall.Add(nextIndex);
                indexWall.Add(index + pathPoints1.Count);

                indexWall.Add(nextIndex);
                indexWall.Add(nextIndex + pathPoints1.Count);
                indexWall.Add(index + pathPoints1.Count);
            }
            indxs.AddRange(indxs1);
            indxs.AddRange(indxs2);
            indxs.AddRange(indexWall);
            indxs.Reverse();
            pathPointsAll.AddRange(pathPoints1);
            pathPointsAll.AddRange(pathPoints2);

            Mesh mesh = new Mesh();
            mesh.vertices = pathPointsAll.ToArray();
            mesh.triangles = indxs.ToArray();
            mesh.RecalculateNormals();
            mesh.RecalculateBounds();
            return mesh;//GenerateMesh(pathPoints);
        }
    }
}
